package com.frank.core.idempotent.aspect;

import com.frank.core.idempotent.annotation.ApiIdempotent;
import com.frank.core.log.aspect.LogAspect;
import com.frank.framework.exception.BusinessException;
import com.frank.framework.util.RedissonLockUtil;
import com.frank.framework.util.UserUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * api接口幂等性切面
 * @author Frank
 */
@ConditionalOnProperty(value = "spring.redis.enabled", havingValue = "true") // 只有当 spring.redis.enabled=true的时候该接口幂性等切面才生效
@Component
@Aspect
public class ApiIdempotentAspect {

    @Autowired
    private RedissonLockUtil redissonLockUtil;

    private static final Logger logger = LoggerFactory.getLogger(ApiIdempotentAspect.class);

    @Pointcut("@annotation(com.frank.core.idempotent.annotation.ApiIdempotent)")
    public void apiIdempotentPoinCut() {
    }

    @Before("apiIdempotentPoinCut() && @annotation(apiIdempotent)")
    public void doBefore(ApiIdempotent apiIdempotent) {

        int value = apiIdempotent.value();

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        String uri = request.getRequestURI().toString(); // 请求接口uri

        String currentUsername = UserUtils.getCurrentUsername();

        // 以 当前登录用户名#请求路径 为锁对象，即同一个用户在锁时间内（默认1秒）不能重复请求
        String lockKey = currentUsername + "#" + uri;

        Boolean locked = redissonLockUtil.isLocked(lockKey);

        if (locked) {
            throw new BusinessException("操作太频繁了!");
        } else {
            redissonLockUtil.lock(lockKey, value, TimeUnit.SECONDS);
        }


    }
}
